"""
考勤管理视图模块

该模块包含与学生考勤相关的视图函数和表单，用于记录、查询和统计学生的考勤情况，
包括每日考勤记录的创建、更新，以及迟到、请假、违纪情况的统计和预警。
"""
# 标准库导入
from datetime import date, timedelta, datetime
from typing import Optional, Dict, List, Any
from django.db.models import QuerySet

# Django导入
from django.contrib.auth.decorators import login_required
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import render
from django.http import JsonResponse
from django.db.models import Q
from django.db import IntegrityError

# 本地应用导入
from core.models.daily_attendance import DailyAttendance
from core.models.school_schedule import SchoolSchedule
from core.models.leave_request import LeaveRequest
from core.models.discipline import DisciplineRecord
from core.models import StudentClassEnrollment, ClassInfo
from core.views.homework_views import BaseBootstrapForm
from core.views.utils import get_class
from core.utils import log_operation


def get_daily_attendance_records(classinfo: int, date: str) -> QuerySet[DailyAttendance]:
    """
    获取指定班级和日期的每日考勤记录

    :param classinfo: 班级ID
    :type classinfo: int
    :param date: 日期字符串（格式：YYYY-MM-DD）
    :type date: str
    :return: 每日考勤记录查询集
    :rtype: django.db.models.QuerySet
    """
    # 获取班级所有学生ID
    student_ids = StudentClassEnrollment.objects.filter(
        class_id=classinfo
    ).values_list('student_id', flat=True)
    
    # 查询指定日期的考勤记录（按学生排序）
    attendance_records = DailyAttendance.objects.filter(
        student_id__in=student_ids,
        date=date
    ).select_related('student').order_by('student_id')
    
    return attendance_records
   

@login_required
def get_attendance_records(request) -> render:
    """
    获取当前用户班级指定日期的考勤记录，并渲染到页面

    如果未指定日期，则使用当前日期。支持通过prev参数切换日期。

    :param request: 请求对象
    :type request: django.http.HttpRequest
    :return: 渲染后的考勤记录页面
    :rtype: django.http.HttpResponse
    """
    prev = request.GET.get('prev')
    
    if prev is None:
        attendance_date = date.today().strftime('%Y-%m-%d')
    else:
        attendance_date = (date.today() + timedelta(days=int(prev))).strftime('%Y-%m-%d')
    
    user = request.user
    classinfo = get_class(user)
  
    attendance_records = get_daily_attendance_records(classinfo, attendance_date)
    
    return render(
        request,
        'classmanage/attendance_records.html',
        {
            'attendance_records': attendance_records,
            'date': attendance_date,
            'prev': prev
        }
    )


class DailyAttendanceForm(BaseBootstrapForm):
    """
    每日考勤表单

    基于Django的ModelForm，用于创建和更新每日考勤记录
    """
    class Meta:
        model = DailyAttendance
        fields = ['morning_attendance', 'afternoon_attendance', 'evening_attendance', 'cleaning_task_completed']


@login_required
@csrf_exempt
def update_attendance_records(request) -> JsonResponse:
    """
    更新考勤记录视图函数

    处理AJAX请求，更新指定学生在指定日期的考勤记录

    :param request: 请求对象
    :type request: django.http.HttpRequest
    :return: 包含更新状态的JSON响应
    :rtype: django.http.JsonResponse
    """
    # 解析请求参数
    student_id = request.POST.get('student_id')
    attendance_date = request.POST.get('attendance_date')
    attendance_type = request.POST.get('attendance_type')
    attendance_status = request.POST.get('attendance_status')

    # 验证参数
    if not all([student_id, attendance_date, attendance_type, attendance_status]):
        return JsonResponse(
            {'status': 'error', 'message': '缺少必要的参数'}, 
            status=400
        )

    try:
        # 获取或创建考勤记录
        record, created = DailyAttendance.objects.get_or_create(
            student_id=student_id,
            date=attendance_date,
            defaults={
                'morning_attendance': False,
                'afternoon_attendance': False,
                'evening_attendance': False,
                'cleaning_task_completed': False,
            }
        )
    
        # 更新考勤状态
        if attendance_type == 'morning_attendance':
            record.morning_attendance = attendance_status.lower() == 'true' if isinstance(attendance_status, str) else bool(attendance_status)
        elif attendance_type == 'afternoon_attendance':
            record.afternoon_attendance = attendance_status.lower() == 'true' if isinstance(attendance_status, str) else bool(attendance_status)
        elif attendance_type == 'evening_attendance':
            record.evening_attendance = attendance_status.lower() == 'true' if isinstance(attendance_status, str) else bool(attendance_status)
        elif attendance_type == 'cleaning_task_completed':
            record.cleaning_task_completed = attendance_status.lower() == 'true' if isinstance(attendance_status, str) else bool(attendance_status)
        else:
            return JsonResponse(
                {'status': 'error', 'message': '无效的考勤类型'}, 
                status=400
            )
    
        # 保存到数据库
        record.save()
        
        # 记录考勤操作日志
        operation_type = 'create' if created else 'update'
        log_operation(
            user=request.user,
            operation_type=operation_type,
            content_type='DailyAttendance',
            object_id=record.id,
            object_name=f'{record.student.name} {record.date}',
            request=request,
            details=f'{attendance_type}: {attendance_status}'
        )
        
        return JsonResponse({'status': 'success', 'message': '考勤记录更新成功'})
    
    except IntegrityError:
        return JsonResponse(
            {'status': 'error', 'message': '并发冲突：同一学生同一天已有记录'},
            status=409
        )
    except Exception as e:
        return JsonResponse(
            {'status': 'error', 'message': f'更新失败：{str(e)}'},
            status=500
        )


@login_required
@csrf_exempt
def get_student_status(request, classid: int, selected_date: str) -> JsonResponse:
    """
    统计指定班级和日期的学生迟到、请假、违纪情况并预警

    :param request: 请求对象
    :type request: django.http.HttpRequest
    :param classid: 班级ID
    :type classid: int
    :param selected_date: 日期字符串（格式：YYYY-MM-DD）
    :type selected_date: str
    :return: 包含统计结果的JSON响应
    :rtype: django.http.JsonResponse
    """
    # 验证参数
    if not classid or not selected_date:
        return JsonResponse(
            {'status': 'error', 'message': '请提供班级ID和日期'},
            status=400
        )

    try:
        # 解析日期
        selected_date = datetime.strptime(selected_date, '%Y-%m-%d').date()
    except ValueError:
        return JsonResponse(
            {'status': 'error', 'message': '日期格式不正确，请使用 YYYY-MM-DD 格式'},
            status=400
        )

    try:
        # 获取班级信息
        class_info = ClassInfo.objects.get(id=classid)
    except ClassInfo.DoesNotExist:
        return JsonResponse(
            {'status': 'error', 'message': '班级不存在'},
            status=404
        )

    # 获取班级所有学生ID
    student_ids = StudentClassEnrollment.objects.filter(
        class_id=classid
    ).values_list('student_id', flat=True)

    # 统计迟到学生
    late_morning = []
    late_afternoon = []
    late_evening = []

    # 优化查询：使用select_related关联学生信息
    attendance_records = DailyAttendance.objects.filter(
        student_id__in=student_ids,
        date=selected_date
    ).select_related('student')

    for record in attendance_records:
        if not record.morning_attendance:
            late_morning.append(record.student.name)
        if not record.afternoon_attendance:
            late_afternoon.append(record.student.name)
        if not record.evening_attendance:
            late_evening.append(record.student.name)

    # 计算迟到总次数
    all_late_events = late_morning + late_afternoon + late_evening
    total_late_count = len(all_late_events)

    # 统计请假学生
    leave_requests = LeaveRequest.objects.filter(
        student_id__in=student_ids,
        start_date__lte=selected_date,
        end_date__gte=selected_date,
        status='approved'
    ).select_related('student')

    leave_students = [request.student.name for request in leave_requests]

    # 统计违纪学生
    discipline_records = DisciplineRecord.objects.filter(
        student_id__in=student_ids,
        happened_at__date=selected_date
    ).select_related('student')

    discipline_students = [record.student.name for record in discipline_records]

    # 统计每个学生的违规次数并预警
    student_violation_count: Dict[str, int] = {}
    all_violations = late_morning + late_afternoon + late_evening + leave_students + discipline_students

    for student in all_violations:
        student_violation_count[student] = student_violation_count.get(student, 0) + 1

    warning_students = [student for student, count in student_violation_count.items() if count >= 2]

    context = {
        'late_morning': late_morning,
        'late_afternoon': late_afternoon,
        'late_evening': late_evening,
        'leave_students': leave_students,
        'discipline_students': discipline_students,
        'warning_students': warning_students,
        'total_late_count': total_late_count,
        'class_name': class_info.name,
        'selected_date': selected_date.strftime('%Y-%m-%d')
    }

    return render(request, 'classmanage/student_status.html', context)


@login_required
def generate_attendance_report(request) -> JsonResponse:
    """
    生成考勤统计报告

    根据指定的班级和日期范围，生成考勤统计报告，包括迟到率、出勤率等指标

    :param request: 请求对象
    :type request: django.http.HttpRequest
    :return: 包含报告数据的JSON响应
    :rtype: django.http.JsonResponse
    """
    class_id = request.GET.get('class_id')
    start_date = request.GET.get('start_date')
    end_date = request.GET.get('end_date')

    # 验证参数
    if not all([class_id, start_date, end_date]):
        return JsonResponse(
            {'status': 'error', 'message': '缺少必要的参数'},
            status=400
        )

    try:
        # 解析日期
        start_date = datetime.strptime(start_date, '%Y-%m-%d').date()
        end_date = datetime.strptime(end_date, '%Y-%m-%d').date()
    except ValueError:
        return JsonResponse(
            {'status': 'error', 'message': '日期格式不正确，请使用 YYYY-MM-DD 格式'},
            status=400
        )

    try:
        # 获取班级信息
        class_info = ClassInfo.objects.get(id=class_id)
    except ClassInfo.DoesNotExist:
        return JsonResponse(
            {'status': 'error', 'message': '班级不存在'},
            status=404
        )

    # 获取班级所有学生
    students = StudentClassEnrollment.objects.filter(
        class_id=class_id
    ).select_related('student')
    total_students = students.count()

    # 计算日期范围内的总天数
    total_days = (end_date - start_date).days + 1

    # 统计总考勤记录数
    total_records = DailyAttendance.objects.filter(
        student_id__in=students.values_list('student_id', flat=True),
        date__range=[start_date, end_date]
    ).count()

    # 统计迟到记录数
    late_records = DailyAttendance.objects.filter(
        student_id__in=students.values_list('student_id', flat=True),
        date__range=[start_date, end_date]
    ).filter(
        Q(morning_attendance=False) | Q(afternoon_attendance=False) | Q(evening_attendance=False)
    ).count()

    # 计算出勤率和迟到率
    attendance_rate = (total_records / (total_students * total_days * 3)) * 100 if total_students * total_days * 3 > 0 else 0
    late_rate = (late_records / (total_records)) * 100 if total_records > 0 else 0

    # 生成报告数据
    report_data = {
        'class_name': class_info.name,
        'start_date': start_date.strftime('%Y-%m-%d'),
        'end_date': end_date.strftime('%Y-%m-%d'),
        'total_students': total_students,
        'total_days': total_days,
        'total_records': total_records,
        'late_records': late_records,
        'attendance_rate': round(attendance_rate, 2),
        'late_rate': round(late_rate, 2)
    }

    return JsonResponse({
        'status': 'success',
        'data': report_data
    })